/**
 * 
 */
package com.wilmar.process.web.taglibs;

import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspWriter;

import org.apache.log4j.Logger;
import org.springframework.web.servlet.tags.RequestContextAwareTag;

import com.opensymphony.xwork2.ActionContext;
import com.wilmar.process.core.ProcessSystemDeclareKeys;
import com.wilmar.process.enumerate.EnumProcessBeanIdSet;
import com.wilmar.process.enumerate.EnumProcessSystemTagFixedVariableNameSet;
import com.wilmar.process.enumerate.EnumProcessTagSupportPublicAttribute;
import com.wilmar.process.enumerate.EnumTagLibParameterScope;
import com.wilmar.process.enumerate.EnumTagLibResource;
import com.wilmar.process.exception.DirtyDataException;
import com.wilmar.process.exception.NoUserSessionException;
import com.wilmar.process.exception.UnSupportedClassConvertorException;
import com.wilmar.process.system.ProcessSystem;
import com.wilmar.process.web.spi.IUserSessionService;

/**
 * @author MaKuBEX E-mail:makubexnet@gmail.com
 * @version 1.0.0 at Aug 2, 2009 4:40:53 PM
 * 
 */
public abstract class ProcessTagSupport extends RequestContextAwareTag {

	/**
	 * @serialField
	 */
	private static final long serialVersionUID = 5245458559506998560L;

	private static final Logger log = Logger.getLogger(ProcessTagSupport.class);

	protected static final String TRUE = "true";
	protected static final String FALSE = "false";

	protected String id;
	protected String name;
	protected String cssStyle;
	protected String readonly;
	protected String cssClass;

	protected String onclick;
	protected String onsubmit;

	protected String processInstanceId;
	protected String taskInstanceId;
	protected String processDefinitionId;

	private ResourceBundle bundle;

	/**
	 * 增加指定的属性
	 * 
	 * @param html
	 *            html上下文
	 * @param attributeName
	 *            属性名称
	 * @param attributeValue
	 *            属性值
	 * @param defaultValue
	 *            默认值
	 */
	protected void appendAttribute(StringBuffer html, String attributeName,
			Object attributeValue, String defaultValue) {
		String sValue = null;
		try {
			sValue = this.validateAttributeValue(attributeValue);
		} catch (DirtyDataException e) {
			sValue = defaultValue;
		}
		if (sValue != null) {
			html.append(ProcessSystemDeclareKeys.SPACE);
			html.append(attributeName);
			html.append(ProcessSystemDeclareKeys.EQUAL);
			html.append(ProcessSystemDeclareKeys.DOULBE_QUOTES);
			html.append(sValue);
			html.append(ProcessSystemDeclareKeys.DOULBE_QUOTES);
			html.append(ProcessSystemDeclareKeys.SPACE);
		}
	}

	/**
	 * 增加指定的属性
	 * 
	 * @param html
	 *            html上下文
	 * @param attributeName
	 *            属性名称
	 * @param attributeValue
	 *            属性值
	 */
	protected void appendAttribute(StringBuffer html, String attributeName,
			Object attributeValue) {
		String sValue = null;
		try {
			sValue = this.validateAttributeValue(attributeValue);
		} catch (DirtyDataException e) {
			sValue = "";
		}
		if (sValue != null) {
			html.append(ProcessSystemDeclareKeys.SPACE);
			html.append(attributeName);
			html.append(ProcessSystemDeclareKeys.EQUAL);
			html.append(ProcessSystemDeclareKeys.DOULBE_QUOTES);
			html.append(sValue);
			html.append(ProcessSystemDeclareKeys.DOULBE_QUOTES);
			html.append(ProcessSystemDeclareKeys.SPACE);
		}
	}

	/**
	 * 增加公共属性的值
	 * 
	 * @param html
	 *            字符串缓冲对象，通常用于最终生成html代码
	 * @param attribute
	 *            属性名称
	 */
	protected void appendPublicAttribute(StringBuffer html,
			EnumProcessTagSupportPublicAttribute attribute) {
		String value = this.getAttributeValue(attribute);
		if (value != null && value.trim().length() != 0) {
			html.append(ProcessSystemDeclareKeys.SPACE);
			html.append(attribute.getAttributeName());
			html.append(ProcessSystemDeclareKeys.EQUAL);
			html.append(ProcessSystemDeclareKeys.QUOTATION);
			html.append(value);
			html.append(ProcessSystemDeclareKeys.QUOTATION);
			html.append(ProcessSystemDeclareKeys.SPACE);
		}
	}

	/**
	 * 增加公共属性的值，如果没有对应的属性值，则使用提供的默认值
	 * 
	 * @param html
	 *            字符串缓冲对象，通常用于最终生成html代码
	 * @param attribute
	 *            属性名称
	 * @param defaultValue
	 *            默认值
	 */
	protected void appendPublicAttribute(StringBuffer html,
			EnumProcessTagSupportPublicAttribute attribute, String defaultValue) {
		String value = this.getAttributeValue(attribute);
		html.append(ProcessSystemDeclareKeys.SPACE);
		html.append(attribute.getAttributeName());
		html.append(ProcessSystemDeclareKeys.EQUAL);
		html.append(ProcessSystemDeclareKeys.QUOTATION);
		if (value != null && value.trim().length() != 0)
			html.append(value);
		else
			html.append(defaultValue);
		html.append(ProcessSystemDeclareKeys.QUOTATION);
		html.append(ProcessSystemDeclareKeys.SPACE);
	}

	private String convertToString(Object source)
			throws UnSupportedClassConvertorException {
		if (source != null) {
			if (source instanceof String)
				return (String) source;
			else if (source instanceof String[])
				return ((String[]) source)[0];
			else
				throw new UnSupportedClassConvertorException(
						"Could not convert this value to String type, the value is: "
								+ source.toString());
		} else {
			return null;
		}
	}

	/**
	 * 从request或者session中获取属性
	 * 
	 * @param paramName
	 *            属性名称
	 * @return 属性值
	 */
	public String getAttribute(
			EnumProcessSystemTagFixedVariableNameSet paramName) {
		Object rtnValue = this.getRequest().getParameter(paramName.toString());
		if (rtnValue == null)
			rtnValue = this.getRequest().getAttribute(paramName.toString());
		if (rtnValue == null)
			rtnValue = this.getSession().getAttribute(paramName.toString());
		String result = null;
		try {
			result = this.convertToString(rtnValue);
		} catch (UnSupportedClassConvertorException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 根据指定的范围从request或者session中获取属性
	 * 
	 * @param paramName
	 *            属性名称
	 * @param scope
	 *            获取范围
	 * @return 属性值
	 */
	public String getAttribute(
			EnumProcessSystemTagFixedVariableNameSet paramName,
			EnumTagLibParameterScope scope) {
		Object rtnValue = null;
		switch (scope) {
		case REQUEST_PARAMETER:
			rtnValue = this.getRequest().getParameter(paramName.toString());
			break;
		case REQUEST_ATTRIBUTE:
			rtnValue = this.getRequest().getAttribute(paramName.toString());
			break;
		case SESSION_ATTRIBUTE:
			rtnValue = this.getSession().getAttribute(paramName.toString());
			break;
		default:
			rtnValue = this.getAttribute(paramName);
		}
		String result = null;
		try {
			result = this.convertToString(rtnValue);
		} catch (UnSupportedClassConvertorException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 分别从request.parameter/request.attribute/session中获取参数名称对应的属性值并且转换为字符串型
	 * 
	 * @param paramName
	 *            参数名称
	 * @return 参数值
	 */
	protected String getAttribute(String paramName) {
		Object rtnValue = this.getRequest().getParameter(paramName);
		if (rtnValue == null)
			rtnValue = this.getRequest().getAttribute(paramName);
		if (rtnValue == null)
			rtnValue = this.getSession().getAttribute(paramName);
		String result = null;
		try {
			result = this.convertToString(rtnValue);
		} catch (UnSupportedClassConvertorException e) {
			result = rtnValue.toString();
		}
		return result;
	}

	/**
	 * 从指定的范围中获取参数名称对应的属性值并且转换为字符串
	 * 
	 * @param paramName
	 *            参数名称
	 * @param scope
	 *            范围
	 * @return 参数值
	 */
	protected String getAttribute(String paramName,
			EnumTagLibParameterScope scope) {
		Object rtnValue = null;
		switch (scope) {
		case REQUEST_PARAMETER:
			rtnValue = this.getRequest().getParameter(paramName);
			break;
		case REQUEST_ATTRIBUTE:
			rtnValue = this.getRequest().getAttribute(paramName);
			break;
		case SESSION_ATTRIBUTE:
			rtnValue = this.getSession().getAttribute(paramName);
			break;
		default:
			rtnValue = this.getAttribute(paramName);
		}
		String result = null;
		try {
			result = this.convertToString(rtnValue);
		} catch (UnSupportedClassConvertorException e) {
			result = rtnValue.toString();
		}
		return result;
	}

	/**
	 * 获取公共属性对应的值
	 * 
	 * @param attribute
	 *            属性名称
	 * @return 属性值
	 */
	protected String getAttributeValue(
			EnumProcessTagSupportPublicAttribute attribute) {
		String value = null;
		switch (attribute) {
		case NAME:
			value = this.name;
			break;
		case ID:
			value = this.id;
			break;
		case CSSCLASS:
			value = this.cssClass;
			break;
		case CSSSTYLE:
			value = this.cssStyle;
			break;
		case READONLY:
			value = this.readonly;
			break;
		case ONCLICK:
			value = this.onclick;
			break;
		case ONSUBMIT:
			value = this.onsubmit;
			break;
		}
		return value;
	}

	/**
	 * 获取系统中已经被定义的Bean
	 * 
	 * @param beanId
	 *            bean的ID
	 * @return 系统中的bean
	 */
	protected Object getBean(EnumProcessBeanIdSet beanId) {
		return this.getRequestContext().getWebApplicationContext().getBean(
				beanId.getId());
	}

	public String getContextPath() {
		return this.pageContext.getServletContext().getContextPath();
	}

	public String getCssClass() {
		return cssClass;
	}

	public String getCssStyle() {
		return cssStyle;
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	/**
	 * @return the onclick
	 */
	public String getOnclick() {
		return onclick;
	}

	/**
	 * 获取输出对象
	 * 
	 * @return out
	 */
	public JspWriter getOut() {
		return this.pageContext.getOut();
	}

	/**
	 * @return the processDefinitionId
	 */
	public String getProcessDefinitionId() {
		this.processDefinitionId = this
				.getAttribute(EnumProcessSystemTagFixedVariableNameSet.PROCESS_INFORMATION_PROCESS_DEFINITION_ID);
		return processDefinitionId;
	}

	/**
	 * @return the processInstanceId
	 */
	public String getProcessInstanceId() {
		this.processInstanceId = this
				.getAttribute(EnumProcessSystemTagFixedVariableNameSet.PROCESS_INFORMATION_PROCESS_INSTANCE_ID);
		return processInstanceId;
	}

	public String getReadonly() {
		return readonly;
	}

	/**
	 * 获取http请求
	 * 
	 * @return request
	 */
	public ServletRequest getRequest() {
		return this.pageContext.getRequest();
	}

	/**
	 * 获取http会话
	 * 
	 * @return session
	 */
	public HttpSession getSession() {
		return this.pageContext.getSession();
	}

	/**
	 * @return the taskInstanceId
	 */
	public String getTaskInstanceId() {
		this.taskInstanceId = this
				.getAttribute(EnumProcessSystemTagFixedVariableNameSet.PROCESS_INFORMATION_TASK_INSTANCE_ID);
		return taskInstanceId;
	}

	/**
	 * 获取国际化文本内容
	 * 
	 * @param key
	 *            资源键
	 * @return 国际化文本
	 * @throws NoUserSessionException
	 *             无法获取用户语言设置
	 */
	protected String getText(EnumTagLibResource key)
			throws NoUserSessionException {
		return this.getText(key, this.getUserLocale());
	}

	/**
	 * 获取国际化文本内容
	 * 
	 * @param key
	 *            资源键
	 * @param locale
	 *            地区
	 * @return 指定地区对应的国际化文本内容
	 */
	protected String getText(EnumTagLibResource key, Locale locale) {
		if (this.bundle == null) {
			bundle = ResourceBundle.getBundle(this.getClass().getSimpleName(),
					locale);
		}
		if (bundle == null)
			return key.getKey();
		String value = null;
		try {
			value = bundle.getString(key.getKey());
		} catch (MissingResourceException me) {
			log.warn("Couldn't find the result for key:" + key);
			log.debug("Then return the key!");
			value = key.getKey();
		}
		return value;
	}

	public void setCssClass(String cssClass) {
		this.cssClass = cssClass;
	}

	public void setCssStyle(String cssStyle) {
		this.cssStyle = cssStyle;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * @param onclick
	 *            the onclick to set
	 */
	public void setOnclick(String onclick) {
		this.onclick = onclick;
	}

	/**
	 * @param processDefinitionId
	 *            the processDefinitionId to set
	 */
	public void setProcessDefinitionId(String processDefinitionId) {
		this.processDefinitionId = processDefinitionId;
	}

	/**
	 * @param processInstanceId
	 *            the processInstanceId to set
	 */
	public void setProcessInstanceId(String processInstanceId) {
		this.processInstanceId = processInstanceId;
	}

	public void setReadonly(String readonly) {
		this.readonly = readonly;
	}

	/**
	 * @param taskInstanceId
	 *            the taskInstanceId to set
	 */
	public void setTaskInstanceId(String taskInstanceId) {
		this.taskInstanceId = taskInstanceId;
	}

	/**
	 * 验证数据有效性
	 * 
	 * @param attributeValue
	 *            属性值
	 * @return 字符串型属性值
	 * @throws DirtyDataException
	 *             不满足特定条件时抛出该异常
	 */
	private String validateAttributeValue(Object attributeValue)
			throws DirtyDataException {
		if (attributeValue != null) {
			if (attributeValue instanceof String) {
				String sValue = (String) attributeValue;
				if (sValue.trim().length() != 0) {
					return sValue;
				}
			} else if (attributeValue instanceof Integer) {
				Integer iValue = (Integer) attributeValue;
				if (iValue != 0 && !iValue.equals(0))
					return iValue.toString();
			} else if (attributeValue instanceof Long) {
				Long lValue = (Long) attributeValue;
				if (lValue != 0L && !lValue.equals(0L))
					return lValue.toString();
			} else {
				return attributeValue.toString();
			}
		}
		throw new DirtyDataException("Here is some dirty data: "
				+ attributeValue);
	}

	/**
	 * 获取用户当前区域语言设置
	 * 
	 * @return 用户当前区域语言设置
	 * @throws NoUserSessionException
	 */
	protected Locale getUserLocale() throws NoUserSessionException {
		IUserSessionService service = (IUserSessionService) ProcessSystem
				.getBean(EnumProcessBeanIdSet.PROCESS_SYSTEM_WEB_USERSESSIONSERVICE);
		Locale locale = null;
		try {
			locale = service.getUserLocale();
			if (locale == null) {
				ActionContext actionContext = ActionContext.getContext();
				locale = service.getUserLocale(actionContext.getSession());
			}
			if (locale == null) {
				locale = service.getUserLocale(this.getSession());
			}
		} catch (NoUserSessionException e) {
			try {
				ActionContext actionContext = ActionContext.getContext();
				locale = service.getUserLocale(actionContext.getSession());
			} catch (NoUserSessionException e2) {
				locale = service.getUserLocale(this.getSession());
			}
		}
		if (locale == null)
			locale = this.pageContext.getRequest().getLocale();
		return locale;
	}

	/**
	 * @return the onsubmit
	 */
	public String getOnsubmit() {
		return onsubmit;
	}

	/**
	 * @param onsubmit
	 *            the onsubmit to set
	 */
	public void setOnsubmit(String onsubmit) {
		this.onsubmit = onsubmit;
	}
}
